/* Gyroe 1.0.0 */
/* fe_main.c : Starts up the interpreter, setting values for most
   of the important variables. Also processes opening the first file
   sent to the interpreter. */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "fe_shared.h"
#include "fe_main.h"

void shutdown_gyroe(int x)
/* J.A -> Until backend is fixed. This way, I can compile and
   link as I go along to catch errors. */
{
    exit(x);
}

static void init_op_result()
{
    int i;

    for (i = 1;i <= 177;i++)
        op_result[i] = T_UNKNOWN;

    op_result[RIGHT_BRACE_N] = T_SEQUENCE;
    op_result[RIGHT_BRACE_2] = T_SEQUENCE;
    op_result[REPEAT] = T_SEQUENCE;
    op_result[APPEND] = T_SEQUENCE;
    op_result[RHS_SLICE] = T_SEQUENCE;
    op_result[CONCAT] = T_SEQUENCE;
    op_result[CONCAT_N] = T_SEQUENCE;
    op_result[PREPEND] = T_SEQUENCE;
    op_result[COMMAND_LINE] = T_SEQUENCE;
    op_result[SPRINTF] = T_SEQUENCE;
    op_result[ROUTINE_ID] = T_INTEGER;
    op_result[GETC] = T_INTEGER;
    op_result[OPEN] = T_INTEGER;
    op_result[LENGTH] = T_INTEGER;
    op_result[PLENGTH] = T_INTEGER;
    op_result[IS_AN_OBJECT] = T_INTEGER;
    op_result[IS_AN_ATOM] = T_INTEGER;
    op_result[IS_A_SEQUENCE] = T_INTEGER;
    op_result[COMPARE] = T_INTEGER;
    op_result[EQUAL] = T_INTEGER;
    op_result[FIND] = T_INTEGER;
    op_result[MATCH]  = T_INTEGER;
    op_result[GET_KEY] = T_INTEGER;
    op_result[IS_AN_INTEGER] = T_INTEGER;
    op_result[ASSIGN_I] = T_INTEGER;
    op_result[RHS_SUBS_I] = T_INTEGER;
    op_result[PLUS_I] = T_INTEGER;
    op_result[MINUS_I] = T_INTEGER;
    op_result[PLUS1_I] = T_INTEGER;
    op_result[SYSTEM_EXEC] = T_INTEGER;
    op_result[TIME] = T_ATOM;
    op_result[TASK_STATUS] = T_INTEGER;
    op_result[TASK_SELF] = T_ATOM;
    op_result[TASK_CREATE] = T_ATOM;
    op_result[TASK_LIST] = T_SEQUENCE;
    op_result[PLATFORM] = T_INTEGER;
}

static void swap_args(int argc, char *argv[])
/* Reverse argv so it looks like it did when inputted by the user.
   Begin at one from Argv, since the 0th entry will be 'gyroe', and
   it isn't necessary to keep. */
{
    int i;

    if (argc > 1) {
        GyArgc = argc-1;
        GyArgv = malloc(GyArgc * sizeof(char *));
        for (i = 1;i < argc;i++)
            GyArgv[i-1] = argv[i];
    }
    else {
        GyArgc = 0;
        GyArgv = NULL;
    }
}

int main(int argc, char *argv[])
/* Initialize the main stuff. Will be cleaned up later. */
{
    shift_args(argc, argv); /* backend needs argc + argv for command_line() */
    swap_args(argc, argv);
    init_op_result();
    init_interpreter();

    shutdown_gyroe(0);
}

static void process_env()
/* Process environment variables. */
{
    char *env_var, *var_tok;

    /* Have each make a delimiter character which contains the
       appropriate value. Otherw`ise this'll become a mess of #ifdef's. */
    env_var = getenv("GYHOME");

    if (env_var == NULL)
        fputs("Failed to get the GYHOME environment variable.\n", stderr);
    else {
        var_tok = strtok(env_var, OS_DELIM);
        while (1) {
            include_dirs_extra--; include_dirs_pos++;
            if (include_dirs_extra == -1) {
                include_dirs = (char **)realloc(include_dirs, (include_dirs_pos+4) * sizeof (char *));
                include_dirs_extra = 3;
            }

            include_dirs[include_dirs_pos] = malloc(strlen(var_tok) + 1 * sizeof (char));
            strcpy(include_dirs[include_dirs_pos], var_tok);
            var_tok = strtok(NULL, OS_DELIM);
            if (var_tok == NULL)
                break;
        }
    }

    env_var = getenv("GYINCLUDE");

    if (env_var == NULL)
        fputs("Failed to get the GYINCLUDE environment variable.\n", stderr);
    else {
        var_tok = strtok(env_var, OS_DELIM);
        while (1) {
            include_dirs_extra--; include_dirs_pos++;
            if (include_dirs_extra == -1) {
                include_dirs = (char **)realloc(include_dirs, (include_dirs_pos+4) * sizeof (char *));
                include_dirs_extra = 3;
            }

            include_dirs[include_dirs_pos] = malloc(strlen(var_tok) + 1 * sizeof (char));
            strcpy(include_dirs[include_dirs_pos], var_tok);
            var_tok = strtok(NULL, OS_DELIM);
            if (var_tok == NULL)
                break;
        }
    }
}

static void process_options()
{
    char *src_name, *pwd;
    int src_from_stdin;

    if (GyArgc >= 1) {
        /* Argv[0] is never put into GyArgv since it is always 'gyroe'.
           Therefore, GyArgv[0] contains the file instead.
           If the user's program requires arguments, they should come after
           the file to include. */
        src_name = GyArgv[0];
        src_from_stdin = FALSE;
    }
    else {
        fputs("Gyroe interpreter version 1.0.0 rc1.\n", stdout);
        fputs("Copyright (c) Jesse Adkins.\n", stdout);
        fputs("Made from the Euphoria interpreter by RDS.\n", stdout);
        fputs("Enter a file : ", stdout);

        fgets(fe_buffer, 1204, stdin);

        /* Remove the \n that fgets leaves. */
        fe_buffer[strlen(fe_buffer) - 1] = '\0';

        src_name = malloc(strlen(fe_buffer) + 1 * sizeof(char));
        strncpy(src_name, fe_buffer, strlen(fe_buffer)+1);
        src_from_stdin = TRUE;
    }

    pwd = getenv("PWD");

    if (pwd == NULL) {
        fputs("Failed to get the PWD environment variable.", stderr);
        shutdown_gyroe(0);
    }

    if (lex_open(src_name) == -1) {
        fprintf(stderr, "Couldn't open `%s`\n", src_name);
        shutdown_gyroe(0);
    }

    strcpy(fe_buffer, pwd);
    strcat(fe_buffer, OS_SLASH_STR);
    strcat(fe_buffer, src_name);

    user_files[0] = malloc(strlen(fe_buffer) + 1 * sizeof(char));
    strcpy(user_files[0], fe_buffer);
    current_path = get_file_path(fe_buffer);

    if (src_from_stdin)
        free(src_name);
}

static void init_interpreter()
/* Malloc basic stuff, and open the first file. Then init everything else. */
{
    /* Stores miscellaneous (and sometimes large) things. */
    fe_buffer = malloc(1024 * sizeof (char));
    fe_buffer_max = 1024;

    /* Stores info from the GYHOME and GYINCLUDE environment variables. */
    include_dirs = malloc(4 * sizeof(char *));
    include_dirs_extra = 4; include_dirs_pos = -1;

    /* Stores names of included files. */
    user_files = malloc(8 * sizeof (char *));
    user_files_extra = 7; user_files_pos = 0;

    error_caught = 0;

    /* Must set this now, since lex_open will try to use it. */
    nest_stack_current = -1;

    init_op_result();
    process_env();
    process_options();

    /* Since init_errors just initializes warning_list by malloc'ing blocks for it,
       it's only called in fe_parser.c the first time that OpWarning is set to 1.
       It's useless to initialize warning_list if it's never on, right? */

    /* frontend initialization */
    init_symtab();
    init_scanner();
    init_emit();
    init_parser();
    read_line();
    parser();
    create_IL(); /* Initializes the backend, for now. */
}

